package cn.codeartist.springboot.component.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;

import java.io.IOException;

/**
 * FastJSON Util
 * Use jackson like FastJSON
 *
 * @author 艾江南
 * @date 2020/7/29
 */
public final class JSON {

    private final static ObjectMapper MAPPER;

    static {
        MAPPER = new ObjectMapper();
    }

    /**
     * Object to JSON
     */
    public static String toJSONString(Object obj) {
        try {
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonException(e);
        }
    }

    /**
     * Object to JSON with strategy
     *
     * @see PropertyNamingStrategy
     */
    public static String toJSONString(Object obj, PropertyNamingStrategy strategy) {
        try {
            return new ObjectMapper().setPropertyNamingStrategy(strategy).writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonException(e);
        }
    }

    /**
     * JSON to object
     */
    public static <T> T parseObject(String json, Class<T> clazz) {
        try {
            return MAPPER.readValue(json, clazz);
        } catch (IOException e) {
            throw new JsonException(e);
        }
    }

    /**
     * JSON to object with strategy
     *
     * @see PropertyNamingStrategy
     */
    public static <T> T parseObject(String json, Class<T> clazz, PropertyNamingStrategy strategy) {
        try {
            return new ObjectMapper().setPropertyNamingStrategy(strategy).readValue(json, clazz);
        } catch (IOException e) {
            throw new JsonException(e);
        }
    }

    /**
     * JSON to type reference object
     */
    public static <T> T parseObject(String json, TypeReference<T> type) {
        try {
            return MAPPER.readValue(json, type);
        } catch (IOException e) {
            throw new JsonException(e);
        }
    }

    /**
     * JSON to type reference object with strategy
     *
     * @see PropertyNamingStrategy
     */
    public static <T> T parseObject(String json, TypeReference<T> type, PropertyNamingStrategy strategy) {
        try {
            return new ObjectMapper().setPropertyNamingStrategy(strategy).readValue(json, type);
        } catch (IOException e) {
            throw new JsonException(e);
        }
    }

    /**
     * JSON to json node
     */
    public static JsonNode parseNode(String json) {
        try {
            return MAPPER.readTree(json);
        } catch (IOException e) {
            throw new JsonException(e);
        }
    }

    /**
     * JSON Operate Exception
     */
    public static class JsonException extends RuntimeException {
        public JsonException() {
            super();
        }

        public JsonException(String message) {
            super(message);
        }

        public JsonException(String message, Throwable cause) {
            super(message, cause);
        }

        public JsonException(Throwable cause) {
            super(cause);
        }

        protected JsonException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
        }
    }
}
